/*
 Copyright (C) 2009 QDSS.org
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.qdss.persist.engine;

import java.util.LinkedList;
import java.util.List;

import org.qdss.persist.Entity;
import org.qdss.persist.Field;
import org.qdss.persist.dialect.Dialect;
import org.qdss.persist.engine.entry.ID;
import org.qdss.persist.metadata.MetadataFactory;


/**
 * 
 * 
 * @author <a href="mailto:zhaofang123@gmail.com">FANGFANG ZHAO</a>
 * @since 0.1.0, Feb 14, 2009
 * @version $Id: ComplexFieldSQLs.java 51 2009-05-06 07:45:48Z zhaofang123@gmail.com $
 */
public class ComplexFieldSQLs {
	
	public static final String REFERENCES_MAPPING 	= "ReferencesMapping";
	public static final String RM_UNIQUEID 			= "uniqueId";
	public static final String RM_ENTITY 			= "entity";
	public static final String RM_FIELD 			= "field";
	public static final String RM_RECORDID 			= "recordId";
	public static final String RM_REFERENCEID 		= "referenceId";
	
	private ComplexFieldSQLs() { }

	
	public static String[] formatReferencesMappingUpdateSqls(Field field, ID recordId, ID[] referenceIds, boolean delete) {
		List<String> sqls = new LinkedList<String>();
		if (delete)
			sqls.add(formatReferencesMappingDelete(field, recordId));
		
		for (ID refId : referenceIds) {
			sqls.add(formatReferencesMappingInsert(field, recordId, refId));
		}
		return sqls.toArray(new String[sqls.size()]);
	}
	
	/**
	 * Formatted 
	 * <tt>insert into ReferencesMapping (uniqueId, entity, field, recordId, referenceId) values ('%s', %d, '%s', '%s', '%s')</tt>
	 * 
	 * @param field
	 * @param recordId
	 * @param referenceId
	 * @return
	 */
	public static String formatReferencesMappingInsert(Field field, ID recordId, ID referenceId) {
		return String.format(RM_INSERT_FORMAT,
				ID.newId(RM.getEntityCode()).toLiteral(),
				field.getOwnEntity().getEntityCode(),
				field.getName(),
				recordId.toLiteral(),
				referenceId.toLiteral());
	}
	
	/**
	 * Formatted
	 * <tt>delete from ReferencesMapping where entity = %d and field = '%s' and referenceId = '%s'</tt>
	 * 
	 * @param field
	 * @param recordId
	 * @return
	 */
	public static String formatReferencesMappingDelete(Field field, ID recordId) {
		return String.format(RM_DELETE_FORMAT,
				field.getOwnEntity().getEntityCode(),
				field.getName(),
				recordId.toLiteral());
	}
	
	public static String formatReferencesMappingBaseSelect(Field field, ID recordId) {
		return String.format(RM_SELECT_FORMAT,
				field.getOwnEntity().getEntityCode(),
				field.getName(),
				recordId.toLiteral());
	}
	
	
	private static Entity RM;
	private static String RM_INSERT_FORMAT;
	private static String RM_DELETE_FORMAT;
	private static String RM_SELECT_FORMAT;
	
	protected static void install(MetadataFactory factory, Dialect dialect) {
		RM = factory.getEntity(REFERENCES_MAPPING);
		StringBuilder sql = new StringBuilder("insert into ").append(dialect.quote(RM.getPhysicalName())).append(" ( ");
		sql.append( column(RM_UNIQUEID, 	RM, dialect)).append(", ")
			.append(column(RM_ENTITY, 		RM, dialect)).append(", ")
			.append(column(RM_FIELD, 		RM, dialect)).append(", ")
			.append(column(RM_RECORDID, 	RM, dialect)).append(", ")
			.append(column(RM_REFERENCEID,  RM, dialect));
		RM_INSERT_FORMAT = sql.append(" ) values ( '%s', %d, '%s', '%s', '%s' )").toString();
		sql = null;

		sql = new StringBuilder("delete from ").append(dialect.quote(RM.getPhysicalName()));
		sql.append(" where ")
			.append(column(RM_ENTITY, 		RM, dialect)).append(" = %d and ")
			.append(column(RM_FIELD, 		RM, dialect)).append(" = '%s' and ")
			.append(column(RM_RECORDID, 	RM, dialect)).append(" = '%s'");
		RM_DELETE_FORMAT = sql.toString();
		sql = null;
		
		sql = new StringBuilder("select ").append(RM_REFERENCEID);
		sql.append(" from ").append(RM.getName()).append(" where ")
			.append(RM_ENTITY	).append(" = %d and ")
			.append(RM_FIELD	).append(" = '%s' and ")
			.append(RM_RECORDID	).append(" = '%s'");
		RM_SELECT_FORMAT = sql.toString();
		sql = null;
	}
	
	private static String column(String fName, Entity entity, Dialect dialect) {
		return dialect.quote(entity.getField(fName).getPhysicalName());
	}
}
